package org.springframework.boot.autoconfigure.web.servlet;

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.boot.web.servlet.server.Encoding;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;
//表示这是一个自动配置类。在Spring Boot启动时，如果该类存在，则会自动扫描并加载其依赖项。
@AutoConfiguration
//表示该类可以接收配置属性，并将其存储到运行时环境中。在Spring Boot启动时，如果该类存在，则会自动扫描并加载其配置属性。
@EnableConfigurationProperties({ServerProperties.class})
//表示该注解只在Web应用程序中生效。如果应用程序不是Web应用程序，则该注解将不会生效。
@ConditionalOnWebApplication(type = Type.SERVLET)
//表示该注解只在特定类存在时生效。如果该类不存在，则该注解将不会生效。
@ConditionalOnClass({CharacterEncodingFilter.class})
//表示该注解只在特定属性的值匹配时生效。如果属性的值不匹配，则该注解将不会生效。在本例中，
//该注解用于检查“server.servlet.encoding.enabled”属性是否为true。如果该属性的值为true，则该注解将生效，否则将不会生效。
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = {"enabled"}, matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
    //他已经和SpringBoot的配置文件映射了
    private final Encoding properties;
    //只有一个有参构造器的情况下，参数的值就会从容器中拿
    public HttpEncodingAutoConfiguration(ServerProperties properties) {
        this.properties = properties.getServlet().getEncoding();
    }
    //给容器中添加一个组件，这个组件的某些值需要从properties中获取
    @Bean
    //在Spring容器中查找指定名称的Bean是否存在，如果不存在则创建一个新的Bean并注入到容器中。该注解可以用于创建和注册Bean的时候，
    //也可以用于其他Bean的依赖注入时，如果被依赖的Bean不存在，则自动创建一个新的Bean并注入。
    @ConditionalOnMissingBean
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.web.servlet.server.Encoding.Type.RESPONSE));
        return filter;
    }

    @Bean
    public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
        return new LocaleCharsetMappingsCustomizer(this.properties);
    }

    static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
        private final Encoding properties;

        LocaleCharsetMappingsCustomizer(Encoding properties) {
            this.properties = properties;
        }

        public void customize(ConfigurableServletWebServerFactory factory) {
            if (this.properties.getMapping() != null) {
                factory.setLocaleCharsetMappings(this.properties.getMapping());
            }

        }

        public int getOrder() {
            return 0;
        }
    }
}
